Java Functional Programming এর একটি অত্যন্ত গুরুত্বপূর্ণ এবং শক্তিশালী অংশ হল Streams API, যা Java 8 থেকে পরিচিতি লাভ করেছে। Streams API ব্যবহার করে আপনি ডেটার সাথে কার্যকরীভাবে কাজ করতে পারেন, যেমন ডেটা প্রসেসিং, ফিল্টারিং, ম্যাপিং, এবং অন্যান্য বিভিন্ন ট্রান্সফরমেশন, যা সহজ, পাঠযোগ্য এবং কম্প্যাক্ট কোড তৈরিতে সহায়তা করে।
এখানে, Streams এর Advanced Features নিয়ে আলোচনা করা হবে যা আপনাকে ডেটা প্রসেসিংয়ের জন্য আরও শক্তিশালী এবং নমনীয় পদ্ধতি প্রদান করবে।
1. Streams API Overview
Java-এ Streams API একটি functional approach প্রদান করে ডেটা প্রসেসিং করার জন্য। এর মধ্যে ফিচারগুলো filtering, mapping, reducing, collecting এবং sorting সহ বিভিন্ন কার্যকলাপ অন্তর্ভুক্ত। Streams ইন্টারফেসের মাধ্যমে আপনি data sources থেকে ডেটা প্রক্রিয়া করতে পারেন, যেমন collections, arrays, বা I/O channels।
Basic Stream Example:
import java.util.Arrays;
import java.util.List;
public class StreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
.filter(n -> n % 2 == 0) // Filter even numbers
.forEach(System.out::println); // Print each filtered number
}
}
এই উদাহরণে, filter মেথডটি ব্যবহার করা হয়েছে যা even numbers ফিল্টার করে এবং forEach দিয়ে তাদের প্রিন্ট করা হয়েছে।
2. Advanced Features of Streams
2.1. FlatMap: Transforming Nested Collections
flatMap ব্যবহার করা হয় যখন আপনার একটি Nested Collection বা Stream থাকে এবং আপনি চান যে এর মধ্যে থাকা সমস্ত উপাদানগুলোকে একটি ফ্ল্যাট স্ট্রিমে রূপান্তরিত করতে। এটি Stream of Streams কে একত্রিত করে একটি single Stream তৈরি করে।
Example:
import java.util.Arrays;
import java.util.List;
public class FlatMapExample {
public static void main(String[] args) {
List<List<Integer>> numbers = Arrays.asList(
Arrays.asList(1, 2, 3),
Arrays.asList(4, 5),
Arrays.asList(6, 7, 8)
);
numbers.stream()
.flatMap(List::stream) // Flatten nested List to Stream
.forEach(System.out::println);
}
}
এখানে, flatMap মেথডটি List<List<Integer>> কে Stream<Integer>-এ রূপান্তরিত করেছে।
2.2. Collectors: Collecting Results
Collectors হল Streams API-এর একটি অত্যন্ত শক্তিশালী উপাদান, যা স্ট্রিমের উপাদানগুলোকে একটি কন্টেইনারে (যেমন List, Set, Map) সংগ্রহ করতে সহায়তা করে। Spring বা Java-তে ডেটা সংগ্রহ ও প্রসেসিংয়ের জন্য এটি একটি কার্যকরী পদ্ধতি।
- toList(), toSet(), joining(), groupingBy(), partitioningBy() ইত্যাদি কন্টেইনার প্রসেসিংয়ের জন্য ব্যবহার করা যায়।
Example: Collecting with Collectors.toList():
import java.util.*;
import java.util.stream.Collectors;
public class CollectorExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "cherry", "apple", "date");
List<String> uniqueWords = words.stream()
.distinct() // Remove duplicates
.collect(Collectors.toList()); // Collect to List
System.out.println(uniqueWords);
}
}
এখানে, distinct() ফাংশন ডুপ্লিকেট শব্দগুলো বাদ দিচ্ছে এবং collect() এর মাধ্যমে তা একটি List-এ রূপান্তরিত হচ্ছে।
2.3. GroupingBy: Grouping Elements
groupingBy ব্যবহার করে আপনি একটি স্ট্রিমের উপাদানগুলিকে একটি নির্দিষ্ট ক্রাইটেরিয়াতে গ্রুপ করতে পারেন, যেমন একাধিক কীগুলির উপর ভিত্তি করে ডেটাকে গ্রুপ করা।
Example: Grouping with Collectors.groupingBy():
import java.util.*;
import java.util.stream.Collectors;
public class GroupingByExample {
public static void main(String[] args) {
List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date", "apricot");
Map<Character, List<String>> groupedByFirstLetter = fruits.stream()
.collect(Collectors.groupingBy(fruit -> fruit.charAt(0))); // Group by first letter
groupedByFirstLetter.forEach((key, value) -> System.out.println(key + ": " + value));
}
}
এখানে, groupingBy ফাংশনটি ফলমূলের প্রথম অক্ষরের উপর ভিত্তি করে গ্রুপিং করছে এবং প্রতিটি গ্রুপ প্রিন্ট করছে।
2.4. PartitioningBy: Partitioning Elements into Two Groups
partitioningBy একটি বিশেষ ধরনের groupingBy যেখানে দুটি গ্রুপে ডেটা ভাগ করা হয় (যেমন, সঠিক বা ভুল)। এটি শুধুমাত্র একটি predicate গ্রহণ করে।
Example: Partitioning with Collectors.partitioningBy():
import java.util.*;
import java.util.stream.Collectors;
public class PartitioningByExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
Map<Boolean, List<Integer>> partitioned = numbers.stream()
.collect(Collectors.partitioningBy(n -> n % 2 == 0)); // Partition by even/odd
partitioned.forEach((key, value) -> System.out.println(key + ": " + value));
}
}
এখানে, partitioningBy ফাংশনটি সংখ্যাগুলিকে even এবং odd গ্রুপে ভাগ করছে।
3. Reducing: Accumulating Results
reduce() হল একটি শক্তিশালী ফাংশন যা একটি স্ট্রিমের উপাদানগুলোকে একক মানে রূপান্তরিত করে। এটি অ্যাকিউমুলেটর হিসাবে কাজ করে এবং স্ট্রিমের সকল উপাদানকে একটি ফলাফলে কম্পাইল করতে ব্যবহৃত হয়।
Example: Reducing with reduce()
import java.util.*;
public class ReducingExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b); // Sum the numbers
System.out.println("Sum: " + sum); // Output: Sum: 15
}
}
এখানে, reduce() ফাংশনটি একটি accumulator হিসাবে কাজ করে এবং সমস্ত সংখ্যাকে যোগফল হিসেবে কম্পাইল করে।
4. Lazy Evaluation
Streams এর একটি lazy evaluation সুবিধা রয়েছে, যেখানে স্ট্রিম অপারেশন শুধুমাত্র তখনই কার্যকর হয় যখন ফলাফল প্রয়োজন হয়। এটি stream pipeline অপারেশনগুলিকে যথাযথভাবে প্রক্রিয়া করতে সহায়তা করে, যেমন filter, map, flatMap ইত্যাদি।
Example: Lazy Evaluation
import java.util.Arrays;
import java.util.List;
public class LazyEvaluationExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Lazy evaluation: only executed when 'forEach' is called
numbers.stream()
.filter(n -> n % 2 == 0) // Filter even numbers
.map(n -> n * 2) // Multiply each even number by 2
.forEach(System.out::println); // Print results
}
}
এখানে, filter এবং map অপারেশনগুলো lazy evaluation ভিত্তিতে কাজ করছে, এবং এটি শুধুমাত্র forEach-এ পৌঁছানোর পর এক্সিকিউট হয়।
Java Streams API functional programming এর একটি শক্তিশালী অংশ, যা ডেটা প্রসেসিং এবং ট্রান্সফরমেশনকে অনেক সহজ এবং কার্যকরী করে তোলে।
Advanced Streams Features যেমন flatMap, Collectors, groupingBy, partitioningBy, reduce, এবং lazy evaluation-এর মাধ্যমে আপনি ডেটা পরিচালনা করতে পারবেন আরও শক্তিশালী এবং নমনীয়ভাবে। এটি Java 8 এবং পরবর্তী সংস্করণে ডেটা ম্যানিপুলেশনকে অনেক সহজ এবং পারফরম্যান্স ইফিশিয়েন্ট করে তোলে।
Read more